// ================ 包含头文件 ================ //
#include "lgfx.h"
#include <Adafruit_AHTX0.h>
#include <Adafruit_NeoPixel.h>
#include <ArduinoOTA.h>
#include <Audio.h>
#include <HTTPClient.h>
#include <OneButton.h>
#include <map>
#include <Preferences.h>
#include <esp_ota_ops.h> 

// 网络相关
#define FM_URL "http://lhttp.qtfm.cn/live/%d/64k.mp3"

// ================ 硬件引脚定义 ================ //
// LED相关引脚
#define PIN_LED         48        // RGB LED灯带数据引脚
#define PIN_RGB_LED     47        // 单个RGB LED引脚
#define PIN_LCD_BL      15        // LCD背光控制引脚

// I2S音频接口引脚
#define PIN_I2S_DOUT    5         // I2S数据输出
#define PIN_I2S_BCLK    6         // I2S时钟信号
#define PIN_I2S_LRC     7         // I2S左右声道选择

// 按键和电源管理引脚
#define PIN_KEY_ADD     21        // 音量加/下一首
#define PIN_KEY_MINUS   9         // 音量减/上一首
#define PIN_KEY_MODE    0         // 模式切换键
#define PIN_KEY_POWER   42        // 电源键
#define PIN_POWER_SWITCH 14       // 电源控制引脚
#define PIN_BAT_ADC      1        // 电池电压检测引脚
#define PIN_BAT_CHARGING   2      // 充电状态检测引脚

// ================ 基础配置 ================ //
using namespace std;

// 字体定义
#define FONT16 &fonts::efontCN_16
#define FONT_SMALL &fonts::efontCN_16      // 小字体
#define FONT_MEDIUM &fonts::FreeSans18pt7b // 中等字体
#define FONT_LARGE &fonts::FreeSans24pt7b  // 大字体

// ================ 显示相关常量 ================ //
// 屏幕布局
#define SCREEN_WIDTH    240       // 屏幕宽度
#define SCREEN_HEIGHT   240       // 屏幕高度
#define IP_Y_POS       220       // IP地址显示Y坐标
#define RADIO_INFO_Y_POS 35      // 电台信息Y坐标
#define TIME_Y_POS     120       // 时间显示Y坐标
#define DATE_Y_POS     105       // 日期显示Y坐标

// 音量控制参数
#define VOLUME_BAR_WIDTH  140     // 音量条宽度
#define VOLUME_BAR_HEIGHT 10      // 音量条高度
#define VOLUME_MAX       21       // 最大音量值

// 时间显示常量
#define TIME_Y_POS 120         // 时间显示Y坐标
#define DATE_Y_POS 105         // 日期显示Y坐标

// 颜色定义
#define TFT_BLACK     0x0000
#define TFT_WHITE     0xFFFF
#define TFT_CYAN      0x07FF
#define TFT_ORANGE    0xFD20
#define TFT_BG_COLOR  0x18E0  // 深蓝色背景
#define TFT_PRIMARY_COLOR TFT_CYAN
#define TFT_SECONDARY_COLOR TFT_WHITE
#define TFT_HIGHLIGHT_COLOR 0xFD20  // 橙色
#define TFT_WARNING_COLOR TFT_YELLOW
#define TFT_ERROR_COLOR TFT_RED
#define TFT_TECH_BORDER   0x4D3C  // 科技蓝边框色
#define TFT_TECH_LINE     0x2B5D  // 深蓝装饰线

// 字体定义
#define FONT_SMALL &fonts::efontCN_16  // 小字体
#define FONT_MEDIUM &fonts::FreeSans18pt7b  // 中等字体
#define FONT_LARGE &fonts::FreeSans24pt7b  // 改为粗体大字体

#define BAT_MAX_VOL     4.2       // 满电电压
#define BAT_MIN_VOL     3.3       // 最低电压
#define ADC_RESOLUTION  4095.0    // ADC分辨率
#define ADC_REF_VOL     3.3       // ADC参考电压
#define BAT_VOLTAGE_CALIBRATION 1.046  // 电压校准系数

#define BAT_SHUTDOWN_VOL  3.3       // 自动关机电压阈值
#define BAT_WARNING_VOL   3.5      // 低电量警告电压阈值
#define LOW_BAT_CHECK_INTERVAL 60000 // 低电量检查间隔(ms)

void showVolume() ;

// 平滑处理相关变量
float batteryVoltage = 0.0;       // 电池电压
int batteryLevel = 0;             // 电池电量百分比
float smoothedVoltage = 0.0;      // 平滑后的电压值
const float ALPHA = 0.1;          // 平滑系数（0.0-1.0，越小越平滑）

typedef struct {
  u32_t id;
  String name;
} RadioItem;

static const char *WEEK_DAYS[] = {"日", "一", "二", "三", "四", "五", "六"};
long check1s = 0, check10ms = 0, check300ms = 0, check60s = 0;
char buf[128] = {0};
LGFX tft;
LGFX_Sprite sp(&tft);
Audio audio;
int curIndex = 0;
int curVolume = 6;
int lastRadioIndex = -1; // 记录上次显示的电台索引
Adafruit_NeoPixel pixels(4, PIN_LED, NEO_GRB + NEO_KHZ800);
Adafruit_AHTX0 aht;
Preferences preferences;
std::map<u32_t, OneButton *> buttons;
std::vector<RadioItem> radios = {
    {4915, "清晨音乐台"},
    {1223, "怀旧好声音"},
    {4866, "浙江音乐调频"},
    {20211686, "成都年代音乐怀旧好声音"},
    {1739, "厦门音乐广播"},
    {1271, "深圳飞扬971"},
    {20240, "山东经典音乐广播"},
    {20500066, "年代音乐1022"},
    {1296, "湖北经典音乐广播"},
    {267, "上海经典947"},
    {20212426, "崂山921"},
    {20003, "天津TIKI FM100.5"},
    {1111, "四川城市之音"},
    {4936, "江苏音乐广播PlayFM897"},
    {4237, "长沙FM101.7城市之声"},
    {1665, "山东音乐广播"},
    {1947, "安徽音乐广播"},
    {332, "北京音乐广播"},
    {4932, "山西音乐广播"},
    {20500149, "两广之声音乐台"},
    {4804, "怀集音乐之声"},
    {1649, "河北音乐广播"},
    {4938, "江苏经典流行音乐"},
    {1260, "广东音乐之声"},
    {273, "上海流行音乐LoveRadio"},
    {274, "上海动感101"},
    {2803, "苏州音乐广播"},
    {839, "哈尔滨音乐广播"},
    {5021381, "959年代音乐怀旧好声音"},
    {15318569, "AsiaFM 亚洲粤语台"},
    {5022308, "500首华语经典"},
    {20500150, "顺德音乐之声"},
    {4875, "FM950广西音乐台"},
    {1283, "江门旅游之声"},
    {1936, "FM954汽车音乐广播"},
    {20847, "FM88.6长沙音乐广播"},
    {1612, "西安音乐广播"},
    {20210755, "星河音乐"},
    {1886, "内蒙古音乐之声"},
    {1208, "河南音乐广播"},
    {4963, "南京音乐广播"},
    {1802, "江西音乐广播"},
    {15318146, "杭州FM90.7"},
    {647, "重庆音乐广播"},
    {15318703, "欧美音乐88.7"},
    {5021523, "惠州音乐广播"},
    {15318341, "AsiaFM HD音乐台"},
    {20769, "南宁经典1049"},
    {1289, "楚天音乐广播"},
    {4873, "陕西音乐广播"},
    {5022474, "武安融媒综合广播"},
    {21209, "东莞音乐广播"},
    {4969, "黑龙江音乐广播"},
    {1136, "嘉兴音乐广播"},
    {21275, "南通音乐广播"},
    {20211619, "怀旧音乐广播895"},
    {4981, "芒果时空音乐台"},
    {1297, "武汉经典音乐广播"},
    {20211638, "定州交通音乐广播"},
    {5022023, "上海KFM981"},
    {20207761, "80后音悦台"},
    {1654, "石家庄音乐广播"},
    {20212227, "经典FM1008"},
    {1149, "1003温州音乐之声"},
    {1671, "济南音乐广播FM88.7"},
    {5021912, "AsiaFM 亚洲经典台"},
    {1084, "大连1067"},
    {1892, "包头汽车音乐广播"},
    {1110, "四川岷江音乐广播"},
    {1831, "吉林音乐广播"},
    {5022405, "AsiaFM 亚洲音乐台"},
    {4581, "亚洲音乐成都FM96.5"},
    {20071, "AsiaFM 亚洲天空台"},
    {20033, "1047 Nice FM"},
    {4930, "FM102.2亲子智慧电台"},
    {4846, "893音乐广播"},
    {20026, "郁南音乐台"},
    {1608, "陕西故事广播·年代878"},
    {4923, "徐州音乐广播FM91.9"},
    {4878, "海南音乐广播"},
    {20211575, "经典983电台"},
    {4594, "潮州交通音乐广播"},
    {20500097, "经典音乐广播FM94.8"},
    {4885, "陕西青少广播·好听1055"},
    {4585, "福建音乐广播"},
    {2799, "常州音乐广播"},
    {1975, "MUSIC876"},
    {5022391, "Easy Fm"},
    {20500067, "FM95.9清远交通音乐广播"},
    {20211620, "流行音乐广播999正青春"},
    {20067, "贵州FM91.6音乐广播"},
    {5021902, "沧州音乐广播FM103.6"},
    {20207781, "眉山交通音乐广播"},
    {2811, "湖州交通文艺广播"},
    {5022050, "FM89.1吴江综合广播"},
    {20500053, "经典958"},
    {5022520, "盛京FM105.6"},
    {20091, "中国校园之声"},
    {4979, "89.3芒果音乐台"},
    {20835, "秦皇岛音乐广播"},
    {20211678, "廊坊飞扬105"},
    {1677, "青岛音乐体育广播"},
    {4029, "新疆MIXFM1039"},
    {5022338, "冰城1026哈尔滨古典音乐广播"},
    {20207762, "河南经典FM"},
    {4921, "郑州音乐广播"},
    {5022610, "察布查尔FM99.5"},
    {4871, "唐山音乐广播"},
    {1683, "烟台音乐广播FM105.9"},
    {5020, "滁州旅游交通广播"},
    {20440, "新疆昌吉 FM103.3综合广播"},
    {20212387, "凤凰音乐"},
    {20500187, "云梦音乐台"},
};


void initPowerManager(){
  pinMode(PIN_BAT_CHARGING, INPUT_PULLUP);
  pinMode(PIN_KEY_POWER, INPUT);
  pinMode(PIN_POWER_SWITCH, OUTPUT);
  digitalWrite(PIN_POWER_SWITCH, HIGH);
}


void inline initAudioDevice() {
  audio.setPinout(PIN_I2S_BCLK, PIN_I2S_LRC, PIN_I2S_DOUT);
  audio.setVolume(curVolume);
}

void inline initPixels() {
  pinMode(PIN_RGB_LED, OUTPUT);
  digitalWrite(PIN_RGB_LED, LOW);
  pixels.begin();
  pixels.setBrightness(40);
  pixels.clear();
  pixels.show();
}

void inline autoConfigWifi() {
    int count = 0;
    
    // 创建配网信息显示精灵
    LGFX_Sprite wifiSprite(&tft);
    wifiSprite.createSprite(SCREEN_WIDTH, 60);
    wifiSprite.setFont(FONT_SMALL);
    
    // 显示开始连接信息
    wifiSprite.fillSprite(TFT_BLACK);
    wifiSprite.setTextColor(TFT_PRIMARY_COLOR, TFT_BLACK);
    wifiSprite.drawCentreString("正在连接WiFi...", SCREEN_WIDTH/2, 10);
    wifiSprite.pushSprite(0, 90);
    
    WiFi.mode(WIFI_MODE_STA);
    WiFi.begin();
    
    for (int i = 0; WiFi.status() != WL_CONNECTED && i < 100; i++) {
        delay(100);
    }
    
    if (WiFi.status() != WL_CONNECTED) {
        WiFi.mode(WIFI_MODE_APSTA);
        WiFi.beginSmartConfig();
        
        // 显示配网模式信息
        wifiSprite.fillSprite(TFT_BLACK);
        wifiSprite.setTextColor(TFT_WARNING_COLOR, TFT_BLACK);
        wifiSprite.drawCentreString("请使用ESPTouch配网", SCREEN_WIDTH/2, 10);
        wifiSprite.drawCentreString("长按电源键关机", SCREEN_WIDTH/2, 35);
        wifiSprite.pushSprite(0, 90);
        
        while (WiFi.status() != WL_CONNECTED) {
            delay(100);
            if(digitalRead(PIN_KEY_POWER) == 0){
                if(++count >= 5){ 
                    wifiSprite.fillSprite(TFT_BG_COLOR);
                    wifiSprite.setTextColor(TFT_ERROR_COLOR, TFT_BG_COLOR);
                    wifiSprite.drawCentreString("正在关机...", SCREEN_WIDTH/2, 10);
                    wifiSprite.pushSprite(0, 90);
                    delay(500);
                    digitalWrite(PIN_POWER_SWITCH, LOW);
                }
            }else{
                count = 0;
            }
        }
        WiFi.stopSmartConfig();
        WiFi.mode(WIFI_MODE_STA);
    }
    
    // 显示连接成功信息
    wifiSprite.fillSprite(TFT_BLACK);
    wifiSprite.setTextColor(TFT_HIGHLIGHT_COLOR, TFT_BLACK);
    wifiSprite.drawCentreString("WiFi连接成功", SCREEN_WIDTH/2, 10);
    // 添加IP显示
    sprintf(buf, "IP: %s", WiFi.localIP().toString().c_str());
    wifiSprite.setTextColor(TFT_SECONDARY_COLOR, TFT_BLACK);
    wifiSprite.drawCentreString(buf, SCREEN_WIDTH/2, 35);
    wifiSprite.pushSprite(0, 90);
    delay(1000);

    // 清理显示
    wifiSprite.deleteSprite();
    tft.clear();
}

void showCurrentTime() {
    struct tm timeinfo;
    if(!getLocalTime(&timeinfo)) {
        // 使用Sprite确保背景纯净
        LGFX_Sprite statusSprite(&tft);
        statusSprite.createSprite(240, 30);
        statusSprite.fillSprite(TFT_BG_COLOR);
        statusSprite.setTextColor(TFT_WARNING_COLOR, TFT_BG_COLOR);
        statusSprite.drawCentreString("时间同步中...", 120, 5, FONT_MEDIUM);
        statusSprite.pushSprite(0, TIME_Y_POS);
        statusSprite.deleteSprite();
        return;
    }

    // 1. 日期显示（独立Sprite保证背景纯净）
    sp.createSprite(240, 20);
    sp.fillSprite(TFT_BG_COLOR); // 强制背景色
    sp.setTextColor(TFT_SECONDARY_COLOR, TFT_BG_COLOR);
    sp.setFont(FONT_SMALL);
    sprintf(buf, "%04d年%02d月%02d日 星期%s", 
            timeinfo.tm_year+1900, 
            timeinfo.tm_mon+1, 
            timeinfo.tm_mday,
            WEEK_DAYS[timeinfo.tm_wday]);
    sp.drawCentreString(buf, 120, 0);
    sp.pushSprite(0, DATE_Y_POS);
    sp.deleteSprite();

    // 2. 时间显示（加大字体）
    sp.createSprite(240, 60);  // 增加高度以适应更大字体
    sp.fillSprite(TFT_BG_COLOR);
    sp.setTextColor(TFT_PRIMARY_COLOR, TFT_BG_COLOR);
    sp.setFont(FONT_LARGE);  // 使用更大的字体
    sprintf(buf, "%02d:%02d:%02d", 
            timeinfo.tm_hour,
            timeinfo.tm_min,
            timeinfo.tm_sec);
    sp.drawCentreString(buf, 120, 10);  // 调整垂直位置
    sp.pushSprite(0, TIME_Y_POS);
    sp.deleteSprite();
}

void inline startConfigTime() {
  const int timeZone = 8 * 3600;
  configTime(timeZone, 0, "ntp6.aliyun.com", "cn.ntp.org.cn", "ntp.ntsc.ac.cn");
  
  // 修改为非阻塞等待，最多等待3秒
  int retryCount = 0;
  while (time(nullptr) < 8 * 3600 * 2 && retryCount < 10) {
      delay(300);
      retryCount++;
  }
}

void inline setupOTAConfig() {
  ArduinoOTA.onStart([] {
    audio.stopSong();
    tft.setBrightness(200);
    tft.clear();
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.drawCentreString("软件升级", 120, 8, FONT16);
    tft.drawRoundRect(18, 158, 204, 10, 3, TFT_ORANGE);
    tft.drawCentreString("正在升级中，请勿断电...", 120, 190, FONT16);
  });
  ArduinoOTA.onProgress([](u32_t pro, u32_t total) {
    sprintf(buf, "升级进度: %d / %d", pro, total);
    tft.setTextColor(TFT_YELLOW, TFT_BLACK);
    tft.drawCentreString(buf, 120, 120, FONT16);
    if (pro > 0 && total > 0) {
      int pros = pro * 200 / total;
      tft.fillRoundRect(20, 160, pros, 6, 2, TFT_WHITE);
    }
  });
  ArduinoOTA.onEnd([] {
    tft.clear();
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.drawCentreString("升级成功", 120, 60, FONT16);
    tft.drawCentreString("升级已完成，正在重启...", 120, 140, FONT16);
  });
  ArduinoOTA.onError([](ota_error_t e) {
    tft.clear();
    ESP.restart();
  });
  ArduinoOTA.begin();
}


void nextVolume(int offset) {
    int newVol = curVolume + offset;
    newVol = constrain(newVol, 0, VOLUME_MAX);
    
    if(newVol != curVolume) {
        curVolume = newVol;
        audio.setVolume(curVolume);
        preferences.putInt("lastVolume", curVolume);  //保存音量设置
        showVolume(); // 调用更新后的显示函数
    }
}

void showRadioInfo() {
    if (curIndex >= radios.size()) return;
    if (curIndex == lastRadioIndex) return;
    
    auto radio = radios[curIndex];
    lastRadioIndex = curIndex;

    // 创建主精灵缓冲区(大小改为230x50，背景黑色)
    LGFX_Sprite fullSprite(&tft);
    fullSprite.createSprite(230, 50);
    fullSprite.fillSprite(TFT_BLACK);

    // 在缓冲区中创建电台信息精灵(大小与主缓冲区一致)
    LGFX_Sprite radioSprite(&fullSprite);
    radioSprite.createSprite(230, 50);
    radioSprite.fillSprite(TFT_BLACK);
    
    // 绘制科技感边框(加大圆角和线条粗细)
    radioSprite.drawRoundRect(0, 0, 230, 50, 8, TFT_TECH_BORDER);
    radioSprite.drawRoundRect(1, 1, 228, 48, 7, TFT_TECH_BORDER);
    
    // 显示电台序号和名称（添加滚动效果）
    radioSprite.setTextColor(TFT_HIGHLIGHT_COLOR, TFT_BLACK);
    radioSprite.setFont(FONT_SMALL);
    String displayText = String(curIndex+1) + ". " + radio.name;
    
    // 计算文本宽度
    int textWidth = radioSprite.textWidth(displayText);
    int maxWidth = 180; // 最大显示宽度（根据分隔线位置调整）
    
    if(textWidth > maxWidth) {
        // 文本过长，需要滚动显示
        static int scrollPos = 0;
        static unsigned long lastScrollTime = 0;
        
        if(millis() - lastScrollTime > 200) { // 每200ms滚动一次
            scrollPos++;
            if(scrollPos > textWidth - maxWidth + 10) {
                scrollPos = 0;
            }
            lastScrollTime = millis();
        }
        radioSprite.setScrollRect(20, 8, maxWidth, 20); // Y位置上移到8
        radioSprite.drawString(displayText, 20 - scrollPos, 8); // Y位置上移到8
        radioSprite.clearScrollRect();
    } else {
        // 文本长度合适，居中显示
        radioSprite.drawCentreString(displayText, 115, 8); // Y位置上移到8
    }
    
    // 绘制科技感分隔线
    radioSprite.drawLine(20, 28, 110, 28, TFT_TECH_BORDER); // Y位置上移到28
    radioSprite.drawLine(120, 28, 210, 28, TFT_TECH_BORDER); // Y位置上移到28
    radioSprite.fillTriangle(112, 26, 118, 26, 115, 30, TFT_TECH_BORDER); // 三角形也相应上移
    
    // 显示电台信息
    radioSprite.setTextColor(0x7BEF, TFT_BLACK);
    radioSprite.setFont(FONT_SMALL);
    sprintf(buf, "ID%d • 64kbps", radio.id);
    radioSprite.drawCentreString(buf, 115, 32); // Y位置调整到32
    
    // 将电台信息精灵推送到完整区域精灵
    radioSprite.pushSprite(&fullSprite, 0, 0); // 直接完全覆盖
    radioSprite.deleteSprite();
    
    // 一次性将完整区域推送到屏幕(调整位置使居中)
    fullSprite.pushSprite(5, RADIO_INFO_Y_POS);
    fullSprite.deleteSprite();
}

// 独立音量映射函数（避免与Arduino map冲突）
int volumeToWidth(int volume) {
    return (volume * VOLUME_BAR_WIDTH) / VOLUME_MAX;
}


void showVolume() {
    // 1. 音量数值显示
    sp.createSprite(50, 20);
    sp.fillSprite(TFT_BLACK);
    sp.setTextColor(TFT_PRIMARY_COLOR, TFT_BLACK);
    sp.setFont(FONT_SMALL);
    sprintf(buf, "VOL:%2d", curVolume);
    sp.drawString(buf, 0, 0);
    sp.pushSprite(5, 220); // 改为IP原来的位置
    sp.deleteSprite();

    // 2. 音量条显示
    int fillWidth = volumeToWidth(curVolume);
    
    sp.createSprite(VOLUME_BAR_WIDTH, VOLUME_BAR_HEIGHT);
    sp.fillSprite(TFT_BLACK);
    
    // 背景边框
    sp.drawRoundRect(0, 0, VOLUME_BAR_WIDTH, VOLUME_BAR_HEIGHT, 3, TFT_SECONDARY_COLOR);
    
    // 前景填充（留2像素边距）
    if(fillWidth > 4) {
        sp.fillRoundRect(2, 2, fillWidth-4, VOLUME_BAR_HEIGHT-4, 2, TFT_HIGHLIGHT_COLOR);
    }
    
    sp.pushSprite(60, 223); // 调整到IP原来的位置
    sp.deleteSprite();
}


// 修改网络状态显示位置
inline void showWiFiStrength(int x, int y) {
    if(WiFi.status() != WL_CONNECTED) return;
    
    int8_t rssi = WiFi.RSSI();
    int strength = 0;
    
    // 将RSSI转换为信号强度等级(0-2)
    if(rssi >= -50) strength = 2;
    else if(rssi >= -70) strength = 1;
    
    // 创建精灵绘制WiFi图标
    LGFX_Sprite wifiSprite(&tft);
    wifiSprite.createSprite(30, 25);
    wifiSprite.fillSprite(TFT_BLACK);
    
    // 绘制信号强度指示
    int centerX = 15;
    int centerY = 20;
    
    // 第一档信号强度 - 小实心圆
    if(strength >= 0) {
        wifiSprite.fillCircle(centerX, centerY, 2, TFT_WHITE);
    }
    
    // 第二、三档信号强度 - 圆弧
    for(int i=1; i<3; i++) {
        if(i <= strength) {
            wifiSprite.fillArc(centerX, centerY, 3 + i*4, 2 + i*4, 225, 315, TFT_WHITE);
        } else {
            wifiSprite.drawArc(centerX, centerY, 3 + i*4, 2 + i*4, 225, 315, 0x2104);
        }
    }
    
    wifiSprite.pushSprite(x, y);
    wifiSprite.deleteSprite();
}

void playNext(int offset) {
    // 计算新电台索引（循环列表）
    int total = radios.size();
    curIndex = (curIndex + offset + total) % total;
    
    // 保存当前电台索引
    preferences.putInt("lastStation", curIndex);

    // 播放新电台
    sprintf(buf, FM_URL, radios[curIndex].id);
    audio.connecttohost(buf);
    
    // 直接显示新电台信息
    showRadioInfo();
}


void onButtonClick(void *p) {
  u32_t pin = (u32_t)p;
  switch (pin) {
  case PIN_KEY_MODE:
    audio.pauseResume();
    break;
  case PIN_KEY_ADD:
    playNext(1);
    break;
  case PIN_KEY_MINUS:
    playNext(-1);
    break;
  default:
    break;
  }
}

void onButtonDoubleClick(void *p) {
  u32_t pin = (u32_t)p;
  switch (pin) {
  case PIN_KEY_ADD:
    nextVolume(1);
    break;
  case PIN_KEY_MINUS:
    nextVolume(-1);
    break;
  default:
    break;
  }
}

// 长按处理函数
void onButtonLongPressStart(void *p) {
  u32_t pin = (u32_t)p;
  LGFX_Sprite shutdownSprite(&tft);
  const esp_partition_t* next_partition;
  esp_err_t err;
  
  switch (pin) {
    case PIN_KEY_ADD:
    shutdownSprite.createSprite(240, 60);
    shutdownSprite.fillSprite(TFT_BLACK);
    shutdownSprite.setTextColor(TFT_ERROR_COLOR, TFT_BLACK);
    shutdownSprite.setFont(FONT_SMALL);
    next_partition = esp_ota_get_next_update_partition(NULL);
    if (next_partition == NULL)
    {
      shutdownSprite.drawCentreString("未找到其他分区", 120, 10);
      shutdownSprite.pushSprite(0, 90);
      delay(1000);
      tft.clear();  
      shutdownSprite.deleteSprite();
      return;
    }
    err = esp_ota_set_boot_partition(next_partition);
    if (err != ESP_OK)
    {
      shutdownSprite.drawCentreString("切换应用失败", 120, 10);
      shutdownSprite.pushSprite(0, 90);
      delay(1000);
      tft.clear();  
      shutdownSprite.deleteSprite();
      return;
    }
    shutdownSprite.drawCentreString("应用切换成功，正在重启...", 120, 10);
    shutdownSprite.pushSprite(0, 90);
    delay(1500);
    shutdownSprite.deleteSprite();
    esp_restart();
    break;
  case PIN_KEY_POWER:
      tft.clear();       // 清屏
      shutdownSprite.createSprite(240, 60);
      shutdownSprite.fillSprite(TFT_BLACK);
      shutdownSprite.setTextColor(TFT_ERROR_COLOR, TFT_BLACK);
      shutdownSprite.setFont(FONT_SMALL);
      shutdownSprite.drawCentreString("正在关机...", 120, 10);
      shutdownSprite.pushSprite(0, 90);
      shutdownSprite.deleteSprite();
      
      delay(1000);  // 显示关机信息
      preferences.end();  // 保存设置
      tft.clear();       // 清屏
      digitalWrite(PIN_POWER_SWITCH, LOW);
      while(1); // 一直等到断电
      break;
  default:
      break;
  }
}

void inline setupButtons() {
  u32_t btnPins[] = {PIN_KEY_ADD, PIN_KEY_MINUS, PIN_KEY_MODE,PIN_KEY_POWER};
  for (auto pin : btnPins) {
    auto *btn = new OneButton(pin);
    btn->attachClick(onButtonClick, (void *)pin); //短按弹起事件注册
    btn->attachDoubleClick(onButtonDoubleClick, (void *)pin); //双击事件
    btn->attachLongPressStart(onButtonLongPressStart, (void *)pin); //长按开始事件
    buttons.insert({pin, btn});
  }
}

void checkButtons() {
  for (auto it : buttons)
  {
    it.second->tick();
  }
}

void inline initTFTDevice() {
  tft.init();
  tft.setBrightness(60);
  tft.setFont(FONT16);
  tft.setColorDepth(8);
  tft.fillScreen(TFT_BLACK);
  sp.setFont(FONT16);
  sp.setColorDepth(8);
}

void showBatteryLevel(int x = 205, int y = 0) {
    static unsigned long lastBatCheckTime = 0;
    
  // 读取ADC值并计算实际电压
  int adcValue = analogRead(PIN_BAT_ADC);
  float currentVoltage = (adcValue / ADC_RESOLUTION * ADC_REF_VOL) * 2 * BAT_VOLTAGE_CALIBRATION;
  
  // 使用指数移动平均进行平滑处理
  if (smoothedVoltage == 0.0) {
      smoothedVoltage = currentVoltage;
  } else {
      smoothedVoltage = (ALPHA * currentVoltage) + ((1.0 - ALPHA) * smoothedVoltage);
  }
  
  // 使用平滑后的电压值计算电量
  batteryVoltage = smoothedVoltage;
  batteryLevel = ((batteryVoltage - BAT_MIN_VOL) / (BAT_MAX_VOL - BAT_MIN_VOL)) * 100;
  batteryLevel = constrain(batteryLevel, 0, 100);
  
  // 低电量检查和自动关机逻辑
  unsigned long currentTime = millis() + LOW_BAT_CHECK_INTERVAL; //加上LOW_BAT_CHECK_INTERVAL偏移，确保上电先检测一次
  if (currentTime - lastBatCheckTime >= LOW_BAT_CHECK_INTERVAL) {
      lastBatCheckTime = currentTime;
      
      // 只在非充电状态下才进行低电量检查
      bool isCharging = (digitalRead(PIN_BAT_CHARGING) == LOW);  // 充电时为低电平
      
      if ((batteryVoltage <= BAT_SHUTDOWN_VOL) && !isCharging) {  // 非充电状态下才提醒和关机
          tft.clear();
          // 创建关机提示精灵
          LGFX_Sprite shutdownSprite(&tft);
          shutdownSprite.createSprite(240, 60);
          shutdownSprite.fillSprite(TFT_BLACK);
          shutdownSprite.setTextColor(TFT_ERROR_COLOR, TFT_BLACK);
          shutdownSprite.setFont(FONT_SMALL);
          shutdownSprite.drawCentreString("电池电量过低", 120, 10);
          shutdownSprite.drawCentreString("系统即将关机...", 120, 30);
          shutdownSprite.pushSprite(0, 90);
          shutdownSprite.deleteSprite();
          
          delay(2000);  // 显示2秒关机提示
          preferences.end();
          digitalWrite(PIN_POWER_SWITCH, LOW);
          while(1);
      }
      else if (batteryVoltage <= BAT_WARNING_VOL) {
          // 创建低电量警告精灵
          LGFX_Sprite warningSprite(&tft);
          warningSprite.createSprite(240, 30);
          warningSprite.fillSprite(TFT_BLACK);
          warningSprite.setTextColor(TFT_WARNING_COLOR, TFT_BLACK);
          warningSprite.setFont(FONT_SMALL);
          warningSprite.drawCentreString("电池电量低，请及时充电", 120, 5);
          warningSprite.pushSprite(0, 90);
          warningSprite.deleteSprite();
          delay(1000);  // 显示1秒警告信息
          tft.fillRect(0, 90, 240, 30, TFT_BLACK); // 清除警告信息
      }
  }
    
    // 创建包含文字和图标的完整精灵
    LGFX_Sprite batSprite(&tft);
    batSprite.createSprite(120, 25);
    batSprite.fillSprite(TFT_BLACK);
    
    // 显示电压
    batSprite.setTextColor(TFT_WHITE, TFT_BLACK);
    batSprite.setFont(FONT_SMALL);
    sprintf(buf, "%.2fV", batteryVoltage);
    batSprite.drawString(buf, 0, 5);

    // 绘制电池图标
    int iconX = 45;
    int iconY = 9;
    
    // 检查充电状态
    bool isCharging = (digitalRead(PIN_BAT_CHARGING) == LOW);
    
    // 绘制电池外框
    batSprite.drawRect(iconX + 2, iconY, 24, 10, TFT_WHITE);
    batSprite.fillRect(iconX + 26, iconY + 2, 2, 6, TFT_WHITE);
    
    // 根据电量和充电状态设置填充颜色
    uint16_t fillColor;
    if (isCharging) {
        fillColor = TFT_CYAN;  // 充电中显示青色
    } else {
        if(batteryLevel > 50) fillColor = TFT_GREEN;
        else if(batteryLevel > 20) fillColor = TFT_YELLOW;
        else fillColor = TFT_RED;
    }
    
    // 绘制电量填充
    int fillWidth = (batteryLevel * 22) / 100;
    if(fillWidth > 0) {
        batSprite.fillRect(iconX + 3, iconY + 1, fillWidth, 8, fillColor);
    }
    
    // 如果在充电，添加闪电符号
    if (isCharging) {
        // 绘制更明显的闪电符号
        const uint16_t FLASH_COLOR = TFT_WHITE;  // 改为白色
        // 闪电主体
        batSprite.fillTriangle(iconX + 11, iconY - 2,  // 顶部
                             iconX + 14, iconY + 4,     // 中间右
                             iconX + 11, iconY + 4,     // 中间左
                             FLASH_COLOR);
        batSprite.fillTriangle(iconX + 11, iconY + 4,  // 中间左
                             iconX + 14, iconY + 4,     // 中间右
                             iconX + 14, iconY + 10,    // 底部
                             FLASH_COLOR);
        // 闪电边缘加亮（可以移除，因为主体已经是白色）
        // batSprite.drawLine(iconX + 11, iconY - 2, iconX + 14, iconY + 4, TFT_WHITE);
        // batSprite.drawLine(iconX + 14, iconY + 4, iconX + 14, iconY + 10, TFT_WHITE);
    }
    
    batSprite.pushSprite(x - 90, y);
    batSprite.deleteSprite();
}

void setup() {
  initPowerManager();
  Serial.begin(115200);
  Serial.println("Hello ESP-S3!!");
  
  // 配置ADC
  analogReadResolution(12);
  analogSetAttenuation(ADC_11db);
  
  // 初始化显示和按键优先，确保可以响应
  initTFTDevice();
  setupButtons();
  initPixels();
  
  // 初始化 Preferences
  preferences.begin("radio", false);
  curIndex = preferences.getInt("lastStation", 0);
  curIndex = constrain(curIndex, 0, radios.size() - 1);
  curVolume = preferences.getInt("lastVolume", 6);
  curVolume = constrain(curVolume, 0, VOLUME_MAX);
  
  // 初始化音频设备
  initAudioDevice();
  
  // WiFi连接
  autoConfigWifi();
  
  // 非关键功能初始化
  startConfigTime();
  setupOTAConfig();
  
  // 显示初始界面
  showWiFiStrength(205, -3);  // Y坐标改为-5
  showBatteryLevel(205, 0);  // Y坐标改为-5
  showCurrentTime();
  showVolume();
  showRadioInfo();
  
  // 尝试播放电台
  sprintf(buf, FM_URL, radios[curIndex].id);
  audio.connecttohost(buf);
}

void loop() {
  // 优先处理按键检测
  checkButtons();
  
  auto ms = millis();
  
  // 处理网络相关功能
  if (WiFi.status() == WL_CONNECTED) {
      audio.loop();
      if (ms - check60s > 60000) {
          check60s = ms;
      }
      if (ms - check1s > 1000) {
          check1s = ms;
          ArduinoOTA.handle();
          digitalWrite(PIN_RGB_LED, check1s % 2 ? LOW : HIGH);
          showBatteryLevel(205, 0);  // Y坐标改为-5
          showWiFiStrength(205, -3);  // Y坐标改为-5
      }
      if (ms - check300ms > 300) {
          check300ms = ms;
          showCurrentTime();
          uint16_t rc = rand() % 65536;
          pixels.fill(rc);
          pixels.show();
      }
  } else {
      // WiFi断开时的处理
      if (ms - check1s > 1000) {
          check1s = ms;
          showBatteryLevel(205, -3);
      }
  }
  
  if (ms - check10ms >= 10) {
      check10ms = ms;
      checkButtons();
  }
}

void audio_info(const char *info) { Serial.println(info); }
void audio_eof_stream(const char *info) { playNext(1); }
